package controllers

import (
	"../../../deps/lessgo/net/httpclient"
	"../../../deps/lessgo/pagelet"
	"../../../deps/lessgo/utils"
	"../../api/schema"
	"../../conf"
	"fmt"
	"io"
	"strconv"
	"strings"
)

const (
	setupApiInitInfo  = "%s://%s:%s/keeper/v1/self/info"
	setupApiInitSetup = "%s://%s:%s/keeper/v1/self/setup-init"
)

type Setup struct {
	*pagelet.Controller
}

func (c Setup) IndexAction() {

}

func (c Setup) InitAction() {
	c.ViewData["addr_default"] = "127.0.0.1"
	c.ViewData["port_default"] = conf.Config.Port
}

func (c Setup) InitPostAction() {

	c.AutoRender = false

	rsp := ResponseJson{
		Status:  400,
		Message: "Bad Request",
	}

	defer func() {
		if rspj, err := utils.JsonEncode(rsp); err == nil {
			io.WriteString(c.Response.Out, rspj)
		}
	}()

	disname := strings.TrimSpace(c.Params.Get("disname"))
	if disname == "" {
		rsp.Message = "Cluster Name can not be null"
		return
	}

	nnum, err := strconv.Atoi(c.Params.Get("nnum"))
	if err != nil || nnum < 1 {
		nnum = 1
	}
	if nnum > 9 {
		nnum = 9
	}

	hosts := map[string]int{}
	peers := []schema.ServPeer{}

	for i := 1; i <= nnum; i++ {

		addr, port := c.Params.Get(fmt.Sprintf("host%v", i)), c.Params.Get(fmt.Sprintf("port%v", i))

		if addr == "" || port == "" {
			rsp.Message = fmt.Sprintf("The Node #%v IP Address or Port is not valid", i)
			return
		}

		requrl := fmt.Sprintf(setupApiInitInfo, "http", addr, port)
		c := httpclient.Get(requrl)
		c.SetTimeout(3e9)

		var jrs struct {
			ResponseJson
			Data schema.ServPeer `json:"data"`
		}
		err := c.ReplyJson(&jrs)
		if err != nil {
			rsp.Message = fmt.Sprintf("Can not connect to %s:%s", addr, port)
			return
		}
		if len(jrs.Data.KeeperId) > 0 {
			rsp.Message = fmt.Sprintf("The Node #%v (IP: %s) Have been configured, Can not be used again", i, addr)
			return
		}

		hostid := strings.ToLower(jrs.Data.Id)
		if v, ok := hosts[hostid]; ok {
			rsp.Message = fmt.Sprintf("The Node #%v conflict with Node #%v", i, v)
			return
		}

		hosts[hostid] = i

		jrs.Data.Addr = addr
		jrs.Data.Port = port

		peers = append(peers, jrs.Data)
	}

	var req struct {
		Data schema.ServSetupInit `json:"data"`
	}
	req.Data.KeeperId = utils.StringNewRand36(8)
	req.Data.KeeperName = disname
	req.Data.KeeperPeerSize = nnum
	req.Data.Peers = peers

	jrq, err := utils.JsonEncode(req)

	for _, v := range peers {

		requrl := fmt.Sprintf(setupApiInitSetup, v.Proto, v.Addr, v.Port)

		c := httpclient.Post(requrl)

		c.SetTimeout(3e9)
		c.Header("ContentType", "application/json; charset=utf-8")
		c.Body(jrq)

		var jrs ResponseJson
		c.ReplyJson(&jrs)
	}

	rsp.Status = 200
	rsp.Message = ""
}
